<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>


    <script>

        // 对象的 constructor 属性 (构造函数)
        // 每一个对象都有constructor属性,值为创建该对象的构造函数

        var num = 123;
        var str = 'hello';
        var boo = true;
        var arr = [1,2,3];
        var obj = {name: '海静'};
        var fun = function (){};
        function Human(n){
            this.name = n;
        }
        var lisi = new Human('李四');

        console.log( num.constructor );// ƒ Number() { [native code] }
        console.log( str.constructor );// ƒ String() { [native code] }
        console.log( boo.constructor );// ƒ Boolean() { [native code] }
        console.log( arr.constructor );// ƒ Array() { [native code] }
        console.log( obj.constructor );// ƒ Object() { [native code] }
        console.log( fun.constructor );// ƒ Function() { [native code] }
        console.log( lisi.constructor );// ƒ Human(n) { this.name = n; }


        // 函数的 prototype 属性
        // 每个函数(通常指构造函数)都有一个prototype属性,值为一个对象即原型对象
        // prototype属性是函数默认的属性,在函数创建时,JS引擎自动添加的属性
        // prototype属性的作用: 所有添加到prototype的属性方法都将被同一个构造函数创建出来的实例对象共享(继承)

         function fn1(){}
        var fn2 = function (){}
        var fn3 = new Function()
        
        function Human(n){
            this.name = n;
        }
        Human.prototype.hehe = '呵呵';// 在原型上添加属性
        Human.prototype.say = function (){// 在原型上添加方法
            console.log( 'hello' );
        }
        console.log( Human.prototype );// {hehe: '呵呵', say: ƒ, constructor: Human}
        
        // zhangsan和lisi是同一个构造函数Human创建的实例对象
        var zhangsan = new Human('张三');
        var lisi = new Human('李四');
        console.log( zhangsan );// Human {name: '张三'}
        console.log( lisi );// Human {name: '李四'}
        
        // zhangsan和lisi都可以共享prototype上面的属性方法
        console.log( zhangsan.hehe );// 呵呵
        console.log( lisi.hehe );// 呵呵
        zhangsan.say();
        lisi.say();
        console.log( zhangsan.constructor );// Human
        console.log( lisi.constructor );// Human 

        console.log( fn1.constructor );// ƒ Function() { [native code] }
        console.log( fn2.constructor );// ƒ Function() { [native code] }
        console.log( fn3.constructor );// ƒ Function() { [native code] }
        console.log( Human.constructor );// ƒ Function() { [native code] }

        console.log( fn1.prototype );// {constructor: ƒn1} 原型对象
        console.log( fn2.prototype );// {constructor: ƒn2} 原型对象
        console.log( fn3.prototype );// {constructor: ƒn3} 原型对象
        console.log( Human.prototype );// {constructor: Human} 原型对象


        // 对象的 __proto__ 属性
        // 每一个对象都有一个隐藏属性__proto__,值为创建该对象的构造函数的prototype属性
        // __proto__属性的作用: 维护原型链

        function Human(n) {
            this.name = n;
        }
        var zhangsan = new Human('张三');
        console.log(zhangsan);
        console.log(zhangsan.__proto__);// Human.prototype = {constructor: Human}
        console.log(zhangsan.__proto__ === Human.prototype);// true

        var num = 123;
        var str = 'hello';
        var boo = true;
        var arr = [1, 2, 3];
        var obj = { name: '海静' };
        var fun = function () { };
        console.log(num.__proto__);// Number.prototype
        console.log(str.__proto__);// String.prototype
        console.log(boo.__proto__);// Boolean.prototype
        console.log(arr.__proto__);// Array.prototype
        console.log(obj.__proto__);// Object.prototype
        console.log(fun.__proto__);// Function.prototype


    </script>
</body>

</html>